#include "stdafx.h"
#include "NtApplication.h"
#include "NtLog.h"
#include "NtScene.h"

NtApplication* g_pkApplication = NULL;

NtApplication::NtApplication(void)
: m_AppClassName("NtApplication")
, m_AppTitle("NtApplication")
, m_pkScene(NULL)
{
	g_pkApplication= this;
}

NtApplication::~NtApplication(void)
{
	g_pkApplication= NULL;
}

BOOL NtApplication::Create(HINSTANCE Instance, 
									unsigned int nWidth, 
									unsigned int nHeight )
{
	m_nWidth = nWidth;
	m_nHeight = nHeight;
	m_hInstance = Instance;

	if (! RegisterAppWindow())
	{
		NtLogOutputLastError();
		return FALSE;
	}

	if (! CreateAppWindow())
	{
		NtLogOutputLastError();
		return FALSE;
	}

	if (! CreateD3DDevice())
	{
		NtLogOutputLastError();
		return FALSE;
	}

	if (! CreateScene())
	{
		return FALSE;
	}

	return TRUE;
}

HWND NtApplication::GetHwnd() const
{
	return m_hWnd;
}

void NtApplication::RunLoop()
{
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	InitTime();

	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			UpdateTime();

			Update( m_dwElapseTime );

			Render();

			Sleep(0);
		}
	}

	ReleaseApplication();
}

LRESULT CALLBACK NtApplication::MessageProc(HWND hWnd, UINT Id,
											WPARAM wParam, LPARAM lParam )
{
	if (g_pkApplication)
	{
		return g_pkApplication->OnMessage(hWnd, Id, wParam, lParam);
	}
	else
	{
		return DefWindowProc(hWnd, Id, wParam, lParam);
	}
}

BOOL NtApplication::RegisterAppWindow()
{
	WNDCLASS wc;
	wc.style		 = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = MessageProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = m_hInstance;
	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = m_AppClassName.c_str();

	return RegisterClass(&wc);
}

BOOL NtApplication::CreateAppWindow()
{
	m_hWnd = CreateWindow(m_AppClassName.c_str(), m_AppTitle.c_str(),
		WS_CAPTION | WS_OVERLAPPED, 0, 0, m_nWidth, m_nHeight,
		NULL, NULL, m_hInstance, NULL);

	if (m_hWnd)
	{
		ShowWindow(m_hWnd, SW_SHOW);
		UpdateWindow(m_hWnd);
	}
	else
	{
		NtLogOutputLastError();
	}

	return m_hWnd != 0;
}

BOOL NtApplication::CreateD3DDevice()
{
	IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
	if(d3d9 == NULL)
	{
		return FALSE;
	}

	D3DCAPS9 caps;	
	d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

	int vp = 0;
	if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
	{
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	}
	else
	{
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	}

	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth				= m_nWidth;
	d3dpp.BackBufferHeight				= m_nHeight;
	d3dpp.BackBufferFormat				= D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount				= 1;
	d3dpp.MultiSampleType				= D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality			= 0;
	d3dpp.SwapEffect					= D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow					= m_hWnd;
	d3dpp.Windowed						= TRUE;
	d3dpp.EnableAutoDepthStencil		= true;
	d3dpp.AutoDepthStencilFormat		= D3DFMT_D24S8;
	d3dpp.Flags							= 0;
	d3dpp.FullScreen_RefreshRateInHz	= D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval			= D3DPRESENT_INTERVAL_IMMEDIATE;

	if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, vp, &d3dpp, &m_pDevice)))
	{
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

		if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, vp, &d3dpp, &m_pDevice)))
		{
			d3d9->Release();
			return FALSE;
		}
	}

	d3d9->Release();

	return TRUE;
}

HINSTANCE NtApplication::GetAppInstance() const
{
	return m_hInstance;
}

NtApplication* NtApplication::GetInstance()
{
	return g_pkApplication;
}

VOID NtApplication::UpdateTime()
{
	m_dwCurrTime = timeGetTime();
	
	m_dwElapseTime= m_dwCurrTime- m_dwLastTime;

	m_dwLastTime = m_dwCurrTime;
}

VOID NtApplication::InitTime()
{
	m_dwCurrTime = timeGetTime();

	m_dwLastTime = m_dwCurrTime;

	m_dwElapseTime= m_dwCurrTime- m_dwLastTime;
}

LPDIRECT3DDEVICE9 NtApplication::GetDevice() const
{
	return m_pDevice;
}

void NtApplication::Update( DWORD dwTimer )
{
	m_pkScene->Update(dwTimer);
}

void NtApplication::Render()
{
	if (! m_bInitApp)
	{
		return;
	}

	m_pkScene->Render();
}

BOOL NtApplication::CreateScene()
{
	m_pkScene = new NtScene;
	m_pkScene->InitScene();
	return TRUE;
}

LRESULT NtApplication::OnMessage( HWND hWnd, UINT Id, WPARAM wParam, LPARAM lParam )
{
	LRESULT hr = 0;

	if (Id == WM_KEYDOWN && wParam == VK_ESCAPE )
	{
		PostQuitMessage(0);
	}

	if (m_pkScene)
	{
		hr= m_pkScene->OnMessage(hWnd, Id, wParam, lParam);
	}

	if ( ! hr )
	{
		hr= DefWindowProc(hWnd, Id, wParam, lParam);
	}

	return hr;
}

void NtApplication::ReleaseApplication()
{
	if (m_pkScene)
	{
		m_pkScene->ReleaseScene();
	}
}
